package com.hfzy.ihk.web.linkcall.biz.KnowledgeBase.type;

import com.google.common.collect.Lists;
import com.hfzy.ihk.common.core.elasticsearch.EsQueryUtils;
import com.hfzy.ihk.common.core.elasticsearch.service.EsBaseServiceImpl;
import com.hfzy.ihk.common.util.Utils;
import com.hfzy.ihk.common.util.uuid.base64uuid.UUIDs;
import com.hfzy.ihk.common.web.WebResult;
import com.hfzy.ihk.facade.linkcall.entity.flow.config.SpeakingPackage;
import com.hfzy.ihk.facade.linkcall.entity.knowledge.type.IndustryType;
import com.hfzy.ihk.facade.linkcall.enums.Bool;
import com.hfzy.ihk.facade.linkcall.enums.CheckStatus;
import com.hfzy.ihk.facade.linkcall.vo.knowledgeBase.DTreeNodeVo;
import com.hfzy.ihk.facade.linkcall.vo.knowledgeBase.TreeNodeVo;
import com.hfzy.ihk.web.linkcall.biz.flow.config.SpeakingPackageBiz;
import com.hfzy.ihk.web.linkcall.dao.IndustryTypeRepository;
import com.hfzy.ihk.web.linkcall.support.annotation.PreProcessParam;
import com.hfzy.ihk.web.linkcall.utils.UserUtils;
import com.hfzy.ihk.web.linkcall.utils.WebResultUtils;
import org.apache.tomcat.util.buf.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.data.elasticsearch.repository.ElasticsearchCrudRepository;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

@Component
public class IndustryTypeBiz  extends EsBaseServiceImpl<IndustryType> {
    @Autowired
    private IndustryTypeRepository industryTypeRepository;

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    @Autowired
    private SpeakingPackageBiz speakingPackageBiz;

    @Override
    protected ElasticsearchCrudRepository getReposity() {
        return industryTypeRepository;
    }

    public WebResult save(IndustryType industryType){
        WebResult webResult = null;
        try {
            Long currentUserId = UserUtils.getCurrentUserId()!=null?UserUtils.getCurrentUserId():0l;
            if(industryType.getId()==null || Utils.isNullString(industryType.getId()) || "null".equals(industryType.getId())){
                industryType.setId(UUIDs.base64UUID());
                industryType.setCreateUserId(currentUserId);
                industryType.setModTime(new Date());
                industryType.setCreateTime(new Date());
                industryType.setModUserId(currentUserId);
            }else{
                industryType.setModUserId(currentUserId);
                industryType.setModTime(new Date());
            }
            Map map = new HashMap();
            map.put("parentId",industryType.getParentId());
            map.put("name",industryType.getName());
            List<IndustryType> industryTypeList = getIndustryTypesList(map);
            if(industryTypeList!=null && !industryTypeList.isEmpty()){
                if(!industryTypeList.stream().map(it->it.getId()).collect(Collectors.toList()).contains(industryType.getId())){
                    webResult = WebResultUtils.getFailCharWebResult("该类型已经存在了！");
                    return webResult;
                }
            }
            industryTypeRepository.save(industryType);
            webResult = WebResultUtils.getSuccessCharWebResult("",0,null);
        }catch (Exception e){
            webResult = WebResultUtils.getExceptionCharWebResult("操作异常 "+e.getMessage());
        }finally {
            if(webResult==null)
                webResult = WebResultUtils.getFailCharWebResult("");
        }
        return webResult;
    }


    public List<IndustryType> getAll(){
        Iterable<IndustryType> industryTypes = industryTypeRepository.findAll();
        List<IndustryType> industryTypeList = Lists.newArrayList(industryTypes);
        return industryTypeList;
    }

    @PreProcessParam
    public List<IndustryType> getIndustryTypesList(Map<String,String> params){
      /*  BoolQueryBuilder boolQueryBuilder = getQueryBuilderByParams(params);
        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(boolQueryBuilder)
                .build();
        return elasticsearchTemplate.queryForList(searchQuery,IndustryType.class);*/
        List<IndustryType> industryTypes = null;
        BoolQueryBuilder boolQueryBuilder = getQueryBuilderByParams(params);
        Iterator<IndustryType> iterator = industryTypeRepository.search(boolQueryBuilder).iterator();
        if (iterator != null) {
            industryTypes = new ArrayList<IndustryType>();
            while (iterator.hasNext()) {
                IndustryType next = iterator.next();
                industryTypes.add(next);
            }
        }
        return industryTypes;
    }

    public Page<IndustryType> getPageByCondition(int pageNum,int pageSize,BoolQueryBuilder boolQueryBuilder,FieldSortBuilder fieldSortBuilder){
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder).withSort(fieldSortBuilder).withPageable(PageRequest.of(pageNum,pageSize));
        return industryTypeRepository.search(builder.build());
    }

    @PreProcessParam
    public Page<IndustryType> getByPage(Map<String,String> params){
        BoolQueryBuilder boolQueryBuilder = getQueryBuilderByParams(params);
        int pageNum = Integer.valueOf(params.get("page"))-1;
        int pageSize = Integer.valueOf(params.get("pageSize"));
        //添加排序字段
        FieldSortBuilder fieldSortBuilder = SortBuilders.fieldSort("createTime").order(SortOrder.DESC);
        return getPageByCondition(pageNum,pageSize,boolQueryBuilder,fieldSortBuilder);
    }



    public BoolQueryBuilder getQueryBuilderByParams(Map<String,String> params){
        BoolQueryBuilder shouldQueryBuilder = QueryBuilders.boolQuery();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        Iterator entries = params.entrySet().iterator();
        while (entries.hasNext()){
            Map.Entry entry = (Map.Entry) entries.next();
            String key = entry.getKey().toString();
            switch (key){
                case "createUserId":
                    QueryBuilder queryBuilder = EsQueryUtils.termQuery("createUserId",params.get("createUserId"));
                    boolQueryBuilder.must(queryBuilder);
                    break;
                case "id":
                    boolQueryBuilder.must(EsQueryUtils.termQuery("id",params.get("id")));
                    break;
                case "parentId":
                    boolQueryBuilder.must(EsQueryUtils.termQuery("parentId",params.get("parentId")));
                    break;
                case "ids":
                    boolQueryBuilder.must(EsQueryUtils.termsQuery("id",params.get("ids").split(",")));
                    break;
                case "createTimeStart"://格式：yyyy-MM-dd HH:mm:ss
                    boolQueryBuilder.must(EsQueryUtils.rangeQuery("createTime", params.get("createTimeStart"),
                            null, true, false));
                    break;
                case "createTimeEnd":
                    boolQueryBuilder.must(EsQueryUtils.rangeQuery("createTime", null,
                            params.get("createTimeEnd"), false, true));
                    break;
                case "name":
                    boolQueryBuilder.must(EsQueryUtils.wildcardQuery("name", "*"+params.get("name")+"*"));
                    break;
                case "businessTypeBaseId":
                    boolQueryBuilder.must(EsQueryUtils.termQuery("businessTypeBaseId", params.get("businessTypeBaseId")));
                    break;
                case "orBusinessTypeBaseId":
                    shouldQueryBuilder.should(EsQueryUtils.termQuery("businessTypeBaseId", params.get("orBusinessTypeBaseId")));
//                    boolQueryBuilder.should(EsQueryUtils.termQuery("businessTypeBaseId", params.get("orBusinessTypeBaseId")));
                    break;
                default:
                    break;
            }
        }
        shouldQueryBuilder.should(boolQueryBuilder);
        return shouldQueryBuilder;
    }

    public WebResult deleteIndustryTypeById(String id){
        WebResult webResult = null;
        try{
            //todo ===> 根据该id 找到 此分支下的子类
            Map param = new HashMap();
            param.put("parentId",id);
            List<IndustryType> industryTypes = getIndustryTypesList(param);
            if(industryTypes!=null && !industryTypes.isEmpty()){
                List<String> names = industryTypes.stream().map(it->it.getName()).collect(Collectors.toList());
//                throw  new Exception("该业务类型已经被使用在行业类型中，如:"+ StringUtils.join(names,','));
                return    WebResultUtils.getFailCharWebResult("删除失败，该业务类型已经被使用在行业类型中，如:"+ StringUtils.join(names,','));
            }
            boolean flag = deleteById(id);
            if(flag){
                webResult = WebResultUtils.getSuccessCharWebResult("",0,null);
            }
        }catch (Exception e){
            webResult = WebResultUtils.getExceptionCharWebResult("");
        }finally {
            if(webResult==null)
                webResult = WebResultUtils.getFailCharWebResult("参数异常");
        }
        return  webResult;
    }

    /**
     *  @param packageId         根据 指定 packageId 返回 该话术包选中的类型集合
     *  @param type              显示的树状类型  treeNode 、 DTree
     *  @param selVal            选中的值
     *  @param includeCommon    是否包含通用型
     *  @return
     * */
    public Map<String, Object> queryByTree(String packageId, String type, String selVal, boolean includeCommon){
        List<IndustryType> industryTypeList = new ArrayList<>();
        if(!Utils.isNullString(packageId)){
            SpeakingPackage speakingPackage = speakingPackageBiz.getSpeakingPackageById(packageId);
            if(speakingPackage!=null){
                List<String> industryTypeIds = speakingPackage.getHadIndustryTypeId();
                Map<String,String> map = new HashMap<>();
                map.put("ids", StringUtils.join(industryTypeIds, ','));
                if(includeCommon){
                    map.put("orBusinessTypeBaseId", "AWfjFSALTTemOBuU7fwJ");//业务类型：通用型
                }
                industryTypeList = getIndustryTypesList(map);
            }
        }else{
            industryTypeList = getAll();
            if(includeCommon == false && industryTypeList!=null && !industryTypeList.isEmpty()){
                List<IndustryType> filterCommons = new ArrayList<>();
                industryTypeList.stream().forEach(it->{
                    if(!"AWfjFSALTTemOBuU7fwJ".equals(it.getBusinessTypeBaseId())){
                        filterCommons.add(it);
                    }
                });
                industryTypeList = filterCommons;
            }
        }
        return  queryByTree(industryTypeList,type,selVal);
    }

    /**
     *  @param packageId        根据 指定 packageId 返回 该话术包选中的类型集合
     *  @param type              显示的树状类型  treeNode 、 DTree
     *  @param selVal            选中的值
     *  @param addTopParent     增加顶级父级元素
     *  @param includeCommon    是否包含通用型的
     *  @return
     * */
    public Map<String, Object> queryByTree(String packageId,String type,String selVal,boolean addTopParent,boolean includeCommon){
        Map<String,Object> map = queryByTree(packageId,type,selVal,includeCommon);
        if(addTopParent == true && map!=null && !map.isEmpty() &&  map.containsKey("data")){
            List list = (ArrayList)map.get("data");
            IndustryType topType = new IndustryType();
            topType.setParentId("0");
            topType.setId("0");
            topType.setName("公共知识库");
            if("treeNode".equals(type)){
                TreeNodeVo treeNodeVo = getTreeNodeVo(topType);
                treeNodeVo.setChildren(list);
                list = new ArrayList();
                list.add(treeNodeVo);
            }else{
                DTreeNodeVo dTreeNodeVo = getDTreeNodeVo(topType);
                dTreeNodeVo.setChildren(list);
                list = new ArrayList();
                list.add(dTreeNodeVo);
            }
            map.put("data",list);
        }
        return map;
    }

    /**
     *  @param industryTypeList 被进行构建树状 集合
     *  @param type              显示的树状类型  treeNode 、 DTree
     *  @param selVal            选中的值
     *  @param addTopParent     增加顶级父级元素
     *  @return
     * */
    public Map<String, Object> queryByTree(List<IndustryType> industryTypeList,String type,String selVal,boolean addTopParent){
        Map<String,Object> map = queryByTree(industryTypeList,type,selVal);
        if(addTopParent == true && map!=null && !map.isEmpty() &&  map.containsKey("data")){
            List list = (ArrayList)map.get("data");
            IndustryType topType = new IndustryType();
            topType.setParentId("0");
            topType.setId("0");
            topType.setName("公共知识库");
            if("treeNode".equals(type)){
                TreeNodeVo treeNodeVo = getTreeNodeVo(topType);
                treeNodeVo.setChildren(list);
                list = new ArrayList();
                list.add(treeNodeVo);
            }else{
                DTreeNodeVo dTreeNodeVo = getDTreeNodeVo(topType);
                dTreeNodeVo.setChildren(list);
                list = new ArrayList();
                list.add(dTreeNodeVo);
            }
            map.put("data",list);
        }
        return map;
    }

    /**
     *  @param industryTypeList 被进行构建树状 集合
     *  @param type              显示的树状类型  treeNode 、 DTree
     *  @param selVal            选中的值
     *  @return
     * */
    public Map<String, Object> queryByTree(List<IndustryType> industryTypeList,String type,String selVal){
        Map<String,Object> resultMap = new HashMap<>();
        if(industryTypeList==null || industryTypeList.isEmpty()){
            resultMap.put("status",new HashMap<String, String>() {
                {
                    put("code", "400");
                    put("message", "数据异常");
                }
            });
            resultMap.put("data",null);
            return  resultMap;
        }
        try{
            List resultVo = new ArrayList();
            if(industryTypeList!=null && !industryTypeList.isEmpty()){
                industryTypeList.forEach(it->{
                    if(Utils.isNullString(it.getParentId())){
                        it.setParentId("0");
                    }
                });
                Map<String,List<IndustryType>> groupByPIdList = industryTypeList.stream().collect(Collectors.groupingBy(IndustryType::getParentId));
                List<IndustryType> topIndustryType = industryTypeList.stream().filter(it->/*it.getAffectType()== AffectType.PRIVATE && */"0".equals(it.getParentId())).collect(Collectors.toList());
                if(type!=null && "treeNode".equals(type)){
                    List<TreeNodeVo> treeNodeVos = new ArrayList<TreeNodeVo>();
                    topIndustryType.forEach(it->{
                        treeNodeVos.add(recursiveTree(it,groupByPIdList,selVal));
                    });
                    resultVo = treeNodeVos;
                }else{
                    List<DTreeNodeVo> dTreeNodeVos = new ArrayList<DTreeNodeVo>();
                    topIndustryType.forEach(it->{
                        dTreeNodeVos.add(recursiveDTree(it,groupByPIdList));
                    });
                    resultVo = dTreeNodeVos;
                }
            }
            if(type!=null && "treeNode".equals(type)){
                resultMap.put("code",0);
                resultMap.put("msg","操作成功");
            }else{
                resultMap.put("status",new HashMap<String, String>() {
                    {
                        put("code", "200");
                        put("message", "操作成功");
                    }
                });
            }
            resultMap.put("data",resultVo);
        }catch (Exception e){
            resultMap.put("status",new HashMap<String, String>() {
                {
                    put("code", "500");
                    put("message", "操作异常 "+e.getMessage());
                }
            });
            resultMap.put("data",null);
        }
        return resultMap;
    }


    /**
     * 递归算法解析成树形结构
     *
     * @param industryType
     * @param groupByPIdList 按parentId 分组后的 集合
     * @return
     * @author jiqinlin
     */
    private TreeNodeVo recursiveTree(IndustryType industryType,Map<String,List<IndustryType>> groupByPIdList,String selVal) {
        //根据cid获取节点对象(SELECT * FROM tb_tree t WHERE t.cid=?)
        TreeNodeVo node = getTreeNodeVo(industryType);
        if(selVal.contains(industryType.getId())){
            node.setSelected("selected");
        }
        //查询cid下的所有子节点(SELECT * FROM tb_tree t WHERE t.pid=?)
        List<IndustryType> childTreeNodes = groupByPIdList.get(node.getValue());
        //遍历子节点
        if(childTreeNodes!=null && !childTreeNodes.isEmpty()){
            for (IndustryType child : childTreeNodes) {
                TreeNodeVo n = recursiveTree(child,groupByPIdList,selVal); //递归
                node.getChildren().add(n);
            }
        }
        return node;
    }


    private DTreeNodeVo recursiveDTree(IndustryType industryType,Map<String,List<IndustryType>> groupByPIdList){
        //根据cid获取节点对象(SELECT * FROM tb_tree t WHERE t.cid=?)
        DTreeNodeVo node = getDTreeNodeVo(industryType);
        //查询cid下的所有子节点(SELECT * FROM tb_tree t WHERE t.pid=?)
        List<IndustryType> childTreeNodes = groupByPIdList.get(node.getId());
        //遍历子节点
        if(childTreeNodes!=null && !childTreeNodes.isEmpty()){
            for (IndustryType child : childTreeNodes) {
                DTreeNodeVo n = recursiveDTree(child,groupByPIdList); //递归
                node.getChildren().add(n);
            }
        }
        return node;
    }

    private TreeNodeVo getTreeNodeVo(IndustryType industryType){
        TreeNodeVo treeNodeVo = new TreeNodeVo();
        treeNodeVo.setValue(industryType.getId());
        treeNodeVo.setName(industryType.getName());
        treeNodeVo.setPid(industryType.getParentId());
        return treeNodeVo;
    }

    private DTreeNodeVo getDTreeNodeVo(IndustryType industryType){
        DTreeNodeVo dTreeNodeVo = new DTreeNodeVo();
        dTreeNodeVo.setId(industryType.getId());
        dTreeNodeVo.setTitle(industryType.getName());
        if(!Utils.isNullString(industryType.getParentId())){
            dTreeNodeVo.setParentId(industryType.getParentId());
        }else{
            dTreeNodeVo.setParentId("0");
        }
        if(!Utils.isNullString(industryType.getBusinessTypeBaseId())){
            dTreeNodeVo.setBusinessTypeBaseId(industryType.getBusinessTypeBaseId());
        }else{
            dTreeNodeVo.setBusinessTypeBaseId("0");
        }

        dTreeNodeVo.setBasicData(new HashMap<String,Object>() {
            {
                put("businessTypeBaseId", dTreeNodeVo.getBusinessTypeBaseId());
            }
        });
        return dTreeNodeVo;
    }


}
